package com.atguigu.gmall.cart.service.impl;

import com.atguigu.gmall.cart.service.CartService;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.util.DateUtil;
import com.atguigu.gmall.model.cart.CartInfo;
import com.atguigu.gmall.model.product.SkuInfo;
import com.atguigu.gmall.product.client.ProductFeignClient;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author tongatong
 * @name CartServiceImpl
 * @description
 * @date 2021/9/23
 * @time 20:45
 */
@Service
public class CartServiceImpl implements CartService {
    @Resource
    private RedisTemplate<String, CartInfo> redisTemplate;
    @Resource
    private ProductFeignClient productFeignClient;

    @Override
    public void addToCart(String userId, Long skuId, Integer skuNum) {
        //首先从redis中获取购物车信息
        //得到购物车的key
        String cartKey = getCartKey(userId);
        //根据key获取购物车信息
        //这里为什么使用redis的hash数据类型？
        //可以将购物车的每一条商品信息，作为一个对象，商品的skuid作为redis中的field，商品信息作为value值
        BoundHashOperations<String, String, CartInfo> boundHashOps = redisTemplate.boundHashOps(cartKey);
        CartInfo cartInfo;
        //原来用户id对应的购物车数据，是否已经包含该商品信息
        if(boundHashOps.hasKey(skuId.toString())) {
            //包含该物品信息，更新操作
            cartInfo = boundHashOps.get(skuId.toString());
            cartInfo.setSkuNum(cartInfo.getSkuNum()+skuNum);
            cartInfo.setIsChecked(1);
            cartInfo.setSkuPrice(productFeignClient.getSkuPrice(skuId));
            cartInfo.setUpdateTime(new Date());
        }else {
            cartInfo = new CartInfo();
            //  给cartInfo 赋值！
            SkuInfo skuInfo = productFeignClient.getSkuInfo(skuId);
            //  给表的字段赋值！
            cartInfo.setUserId(userId);
            cartInfo.setSkuId(skuId);
            cartInfo.setCartPrice(skuInfo.getPrice());
            cartInfo.setSkuNum(skuNum);
            cartInfo.setImgUrl(skuInfo.getSkuDefaultImg());
            cartInfo.setSkuName(skuInfo.getSkuName());
            cartInfo.setCreateTime(new Date());
            cartInfo.setUpdateTime(new Date());
            cartInfo.setSkuPrice(skuInfo.getPrice());
        }
        boundHashOps.put(skuId.toString(), cartInfo);
        setCartKeyExpire(cartKey);
    }

    @Override
    public List<CartInfo> getCartList(String userId, String userTempId) {
        //首先查询临时用户id对应的购物车数据，然后查询用户id对应的购物车数据
        //登录用户后，检查购物车中是否有商品信息，如果有商品的话，和登录后对应的商品进行合并处理
        //临时用户id
        List<CartInfo> noLoginCartInfoList = null;
        if (!StringUtils.isEmpty(userTempId)) {
            BoundHashOperations<String, String, CartInfo> boundHashOps = redisTemplate.boundHashOps(getCartKey(userTempId));
            noLoginCartInfoList = boundHashOps.values();
        }
        //如果为空，说明未登录
        if (StringUtils.isEmpty(userId)) {
            if(CollectionUtils.isEmpty(noLoginCartInfoList))
                //按照最后一次更新时间进行排序
                if (!CollectionUtils.isEmpty(noLoginCartInfoList)) {
                    noLoginCartInfoList.sort((o1,o2)->{
                        //  使用时间进行比较
                        return DateUtil.truncatedCompareTo(o2.getUpdateTime(),o1.getUpdateTime(), Calendar.SECOND);
                    });
                }
            return noLoginCartInfoList;
        }

        //不为空，说明已经登录
        //获取用户id对应的购物车数据
        BoundHashOperations<String, String, CartInfo> boundHashOps = redisTemplate.boundHashOps(getCartKey(userId));
        //判断之前临时用户id下，是否有购物车数据
        //如果未登录购物车数据不为空，则进行合并
        if (!CollectionUtils.isEmpty(noLoginCartInfoList)) {
            noLoginCartInfoList.forEach(noLoginCartInfo -> {
                CartInfo cartInfo;
                if (boundHashOps.hasKey(noLoginCartInfo.getSkuId().toString())) {
                    cartInfo = boundHashOps.get(noLoginCartInfo.getSkuId().toString());
                    cartInfo.setSkuNum(cartInfo.getSkuNum() + noLoginCartInfo.getSkuNum());
                    cartInfo.setCartPrice(productFeignClient.getSkuPrice(noLoginCartInfo.getSkuId()));
                    //合并数据：勾选
                    // 未登录状态选中的商品！
                    if (1 == noLoginCartInfo.getIsChecked()) {
                        cartInfo.setIsChecked(1);
                    }
                }else {
                    cartInfo = noLoginCartInfo;
                    cartInfo.setUserId(userId);
                    cartInfo.setCreateTime(new Date());
                    cartInfo.setUpdateTime(new Date());
                }
                boundHashOps.put(noLoginCartInfo.getSkuId().toString(), cartInfo);
            });
            //删除临时用户购物车
            redisTemplate.delete(getCartKey(userTempId));
            setCartKeyExpire(getCartKey(userId));
        }
        //返回最终购物车数据
        List<CartInfo> cartInfoList = boundHashOps.values();
        if(CollectionUtils.isEmpty(cartInfoList)) {
            return new ArrayList<>();
        }
        //展示购物车列表的时候应该有顺序！ 京东：按照更新时间！ 苏宁：创建时间！
        cartInfoList.sort((o1,o2)->{
            //使用时间进行比较
            return DateUtil.truncatedCompareTo(o2.getUpdateTime(),o1.getUpdateTime(), Calendar.SECOND);
        });
        //返回数据
        return cartInfoList;

    }

    @Override
    public void checkCart(String userId, Integer isChecked, Long skuId) {
        String cartKey = this.getCartKey(userId);
        BoundHashOperations<String, String, CartInfo> boundHashOps = this.redisTemplate.boundHashOps(cartKey);
        CartInfo cartInfo = boundHashOps.get(skuId.toString());
        if(null != cartInfo) {
            cartInfo.setIsChecked(isChecked);
            boundHashOps.put(skuId.toString(), cartInfo);
            this.setCartKeyExpire(cartKey);
        }

    }

    @Override
    public void deleteCart(Long skuId, String userId) {
        BoundHashOperations<String, String, CartInfo> boundHashOps = this.redisTemplate.boundHashOps(this.getCartKey(userId));
        //  判断购物车中是否有该商品！
        if (boundHashOps.hasKey(skuId.toString())){
            boundHashOps.delete(skuId.toString());
            setCartKeyExpire(this.getCartKey(userId));
        }

    }

    @Override
    public List<CartInfo> getCartCheckedList(String userId) {
        //获取该用户下对应的所有购物车信息，然后根据选中状态进行筛选
        List<CartInfo> cartInfoList = new ArrayList<>();
        //获取key
//        String cartKey = getCartKey(userId);
        //根据key，获取数据
        BoundHashOperations<String, String, CartInfo> boundHashOps = redisTemplate.boundHashOps(getCartKey(userId));
        List<CartInfo> cartCachInfoList = boundHashOps.values();
        if (!CollectionUtils.isEmpty(cartCachInfoList)) {
            //过滤出所有选中状态的购物项
            cartInfoList = cartCachInfoList.stream().filter(cartInfo -> cartInfo.getIsChecked() == 1
            ).collect(Collectors.toList());
        }
        return cartInfoList;
    }

    //设置key的过期时间
    private void setCartKeyExpire(String cartKey) {
        redisTemplate.expire(cartKey, RedisConst.USER_CART_EXPIRE, TimeUnit.SECONDS);
    }

    //获取购物车的key
    private String getCartKey(String userId) {
        //定义key user:userId:cart
        return RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
    }
}
